package com.blacktech.dbu.auth.service;

import com.blacktech.dbu.auth.dto.CreateUserRequest;
import com.blacktech.dbu.auth.dto.UpdateUserRequest;
import com.blacktech.dbu.auth.entity.DbuOperationLog;
import com.blacktech.dbu.auth.entity.DbuUser;
import com.blacktech.dbu.auth.repository.OperationLogRepository;
import com.blacktech.dbu.auth.repository.UserRepository;
import com.blacktech.dbu.core.dict.UserStatus;
import com.blacktech.dbu.core.dict.UserType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

/**
 * 用户服务
 *
 * @author Yanyunsong
 */
@Service
@Transactional
public class UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserService.class);

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private OperationLogRepository operationLogRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 创建用户
     */
    public DbuUser createUser(CreateUserRequest request, Long operatorId) {
        // 检查用户名是否已存在
        if (userRepository.existsByUsername(request.getUsername())) {
            throw new RuntimeException("用户名已存在");
        }

        // 检查邮箱是否已存在
        if (request.getEmail() != null && userRepository.existsByEmail(request.getEmail())) {
            throw new RuntimeException("邮箱已存在");
        }

        DbuUser user = new DbuUser();
        BeanUtils.copyProperties(request, user);

        // 加密密码
        user.setPassword(passwordEncoder.encode(request.getPassword()));

        // 设置默认状态
        user.setStatus(UserStatus.ENABLED);
        user.setPasswordChangedTime(LocalDateTime.now());

        DbuUser savedUser = userRepository.save(user);

        // 记录操作日志
        logOperation(operatorId, "CREATE_USER", "创建用户", "USER", savedUser.getId(), null, null);

        logger.info("用户创建成功: {}", savedUser.getUsername());
        return savedUser;
    }

    /**
     * 更新用户
     */
    public DbuUser updateUser(Long userId, UpdateUserRequest request, Long operatorId) {
        DbuUser user = getUserById(userId);

        // 更新用户信息
        if (request.getDisplayName() != null) {
            user.setDisplayName(request.getDisplayName());
        }
        if (request.getEmail() != null) {
            // 检查邮箱是否被其他用户使用
            if (userRepository.existsByEmail(request.getEmail()) &&
                !request.getEmail().equals(user.getEmail())) {
                throw new RuntimeException("邮箱已被其他用户使用");
            }
            user.setEmail(request.getEmail());
        }
        if (request.getUserType() != null) {
            user.setUserType(request.getUserType());
        }
        if (request.getStatus() != null) {
            // 检查是否在操作自己，不能将自己设置为禁用或锁定状态
            if (userId.equals(operatorId) &&
                (request.getStatus() == UserStatus.DISABLED || request.getStatus() == UserStatus.LOCKED)) {
                throw new RuntimeException("不能将自己设置为禁用或锁定状态");
            }
            user.setStatus(request.getStatus());
        }

        DbuUser savedUser = userRepository.save(user);

        // 记录操作日志
        logOperation(operatorId, "UPDATE_USER", "更新用户信息", "USER", userId, null, null);

        logger.info("用户更新成功: {}", savedUser.getUsername());
        return savedUser;
    }

    /**
     * 删除用户
     */
    public void deleteUser(Long userId, Long operatorId) {
        DbuUser user = getUserById(userId);

        // 检查是否在操作自己
        if (userId.equals(operatorId)) {
            throw new RuntimeException("不能删除自己");
        }

        // 防止删除超级管理员
        if (user.getUserType() == UserType.SUPER_ADMIN) {
            throw new RuntimeException("不能删除超级管理员");
        }

        userRepository.delete(user);

        // 记录操作日志
        logOperation(operatorId, "DELETE_USER", "删除用户", "USER", userId, null, null);

        logger.info("用户删除成功: {}", user.getUsername());
    }

    /**
     * 重置密码
     */
    public String resetPassword(Long userId, Long operatorId) {
        DbuUser user = getUserById(userId);

        // 生成临时密码
        String tempPassword = generateTempPassword();

        // 更新密码
        user.setPassword(passwordEncoder.encode(tempPassword));
        user.setPasswordChangedTime(LocalDateTime.now());

        userRepository.save(user);

        // 记录操作日志
        logOperation(operatorId, "RESET_PASSWORD", "重置密码", "USER", userId, null, null);

        logger.info("密码重置成功: {}", user.getUsername());
        return tempPassword;
    }

    /**
     * 修改密码
     */
    public void changePassword(Long userId, String oldPassword, String newPassword) {
        DbuUser user = getUserById(userId);

        // 验证旧密码
        if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
            throw new RuntimeException("原密码不正确");
        }

        // 更新密码
        user.setPassword(passwordEncoder.encode(newPassword));
        user.setPasswordChangedTime(LocalDateTime.now());

        userRepository.save(user);

        // 记录操作日志
        logOperation(userId, "CHANGE_PASSWORD", "修改密码", "USER", userId, null, null);

        logger.info("密码修改成功: {}", user.getUsername());
    }

    /**
     * 启用/禁用用户
     */
    public void toggleUserStatus(Long userId, Long operatorId) {
        DbuUser user = getUserById(userId);

        // 检查是否在操作自己
        if (userId.equals(operatorId)) {
            throw new RuntimeException("不能禁用或启用自己");
        }

        // 切换状态
        UserStatus newStatus = user.getStatus() == UserStatus.ENABLED ?
                              UserStatus.DISABLED : UserStatus.ENABLED;
        user.setStatus(newStatus);

        userRepository.save(user);

        // 记录操作日志
        String operation = newStatus == UserStatus.ENABLED ? "启用用户" : "禁用用户";
        logOperation(operatorId, "TOGGLE_USER_STATUS", operation, "USER", userId, null, null);

        logger.info("{}: {}", operation, user.getUsername());
    }

    /**
     * 锁定用户
     */
    public void lockUser(Long userId, Long operatorId) {
        DbuUser user = getUserById(userId);

        // 检查是否在操作自己
        if (userId.equals(operatorId)) {
            throw new RuntimeException("不能锁定自己");
        }

        user.setStatus(UserStatus.LOCKED);
        user.setLockedTime(LocalDateTime.now());

        userRepository.save(user);

        // 记录操作日志
        logOperation(operatorId, "LOCK_USER", "锁定用户", "USER", userId, null, null);

        logger.info("用户锁定成功: {}", user.getUsername());
    }

    /**
     * 解锁用户
     */
    public void unlockUser(Long userId, Long operatorId) {
        DbuUser user = getUserById(userId);
        user.setStatus(UserStatus.ENABLED);
        user.setLoginFailedCount(0);
        user.setLockedTime(null);

        userRepository.save(user);

        // 记录操作日志
        logOperation(operatorId, "UNLOCK_USER", "解锁用户", "USER", userId, null, null);

        logger.info("用户解锁成功: {}", user.getUsername());
    }

    /**
     * 更新登录失败次数
     */
    public void increaseLoginFailedCount(String username) {
        Optional<DbuUser> userOpt = userRepository.findByUsername(username);
        if (userOpt.isPresent()) {
            DbuUser user = userOpt.get();
            user.setLoginFailedCount(user.getLoginFailedCount() + 1);

            // 检查是否需要锁定账户
            if (user.shouldBeLocked()) {
                user.setStatus(UserStatus.LOCKED);
                user.setLockedTime(LocalDateTime.now());
                logger.warn("用户 {} 因登录失败次数过多被锁定", username);
            }

            userRepository.save(user);
        }
    }

    /**
     * 重置登录失败次数
     */
    public void resetLoginFailedCount(Long userId) {
        DbuUser user = getUserById(userId);
        user.setLoginFailedCount(0);
        if (user.getStatus() == UserStatus.LOCKED) {
            user.setStatus(UserStatus.ENABLED);
            user.setLockedTime(null);
        }
        userRepository.save(user);
    }

    /**
     * 更新最后登录时间
     */
    public void updateLastLoginTime(Long userId) {
        userRepository.updateLastLoginTime(userId, LocalDateTime.now());
    }

    /**
     * 查询用户列表
     */
    @Transactional(readOnly = true)
    public Page<DbuUser> findUsers(String username, String displayName, UserType userType,
                                  UserStatus status, Pageable pageable) {
        return userRepository.findUsersByConditions(username, displayName, userType, status, pageable);
    }

    /**
     * 获取所有用户
     */
    @Transactional(readOnly = true)
    public List<DbuUser> findAllUsers() {
        return userRepository.findAll();
    }

    /**
     * 根据ID获取用户
     */
    @Transactional(readOnly = true)
    public DbuUser getUserById(Long userId) {
        return userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在"));
    }

    /**
     * 根据用户名获取用户
     */
    @Transactional(readOnly = true)
    public Optional<DbuUser> getUserByUsername(String username) {
        return userRepository.findByUsername(username);
    }

    /**
     * 获取所有超级管理员
     */
    @Transactional(readOnly = true)
    public List<DbuUser> getSuperAdmins() {
        return userRepository.findByUserType(UserType.SUPER_ADMIN);
    }

    /**
     * 检查是否是第一个用户（第一个用户自动成为超级管理员）
     */
    @Transactional(readOnly = true)
    public boolean isFirstUser() {
        return userRepository.count() == 0;
    }

    /**
     * 记录操作日志
     */
    private void logOperation(Long userId, String operationType, String operationDesc,
                             String objectType, Long objectId, String ipAddress, String errorMessage) {
        DbuOperationLog log = new DbuOperationLog();
        if (userId != null) {
            log.setUser(userRepository.findById(userId).orElse(null));
        }
        log.setOperationType(operationType);
        log.setOperationDesc(operationDesc);
        log.setObjectType(objectType);
        log.setObjectId(objectId);
        log.setIpAddress(ipAddress);
        log.setOperationResult(errorMessage == null ?
                              DbuOperationLog.OperationResult.SUCCESS :
                              DbuOperationLog.OperationResult.FAILURE);
        log.setErrorMessage(errorMessage);

        operationLogRepository.save(log);
    }

    /**
     * 生成临时密码
     */
    private String generateTempPassword() {
        return UUID.randomUUID().toString().substring(0, 8).toUpperCase();
    }
}